package com.summer.data.connection.session;

import com.summer.data.Jsql;
import com.summer.data.connection.Session;
import com.summer.data.connection.SessionFactory;
import com.summer.data.connection.Utils;
import com.summer.data.dialect.Dialect;
import com.summer.data.exception.SqlException;
import com.summer.data.logging.Logger;
import com.summer.data.logging.LoggerFactory;
import com.summer.data.parameter.ParameterStruct;
import com.summer.data.rs.Extractor;
import com.summer.data.rs.extractor.KeysExtractor;

import java.sql.*;
import java.util.List;

/**
 * @author 345480567@qq.com
 */
public class NormalSession extends AbstractSession implements Session {

    Logger logger = LoggerFactory.getLogger(NormalSession.class);

    protected Connection connection;

    protected int requests = 0;

    public NormalSession(SessionFactory sessionFactory) {
        super(sessionFactory);
    }

    @Override
    public synchronized Connection getConnection() {
        if (connection == null || requests == 0) {
            connection = sessionFactory.getConnection();
        }
        requests++;
        return connection;
    }

    @Override
    public synchronized void close() {
        requests--;
        if (requests == 0) {
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    throw new SqlException(e);
                }
            }
        }
    }

    /**
     * 执行查询
     *
     * 查询是面向数据库连接的，函数执行完毕后，不会关闭数据库连接
     *
     * @param jsql 要执行的 jsql
     * @param extractor 结果提取器
     * @return 结果
     */
    @Override
    public <T> T query(Jsql jsql, Extractor<T> extractor) {
        String sqlString = jsql.getString();

        // 阶段1：准备连接、方言
        Connection conn = getConnection();
        Dialect dialect = getDialect();

        if (Logger.isLogSql()) {
            jsql.print(dialect);
        }

        if (jsql.parameterStructList.size() == 0) {

            Statement stmt = null;
            ResultSet resultSet = null;
            try {
                stmt = conn.createStatement();
                resultSet = stmt.executeQuery(sqlString);

                T t = extractor.extract(resultSet, dialect);
                return t;
            } catch (SQLException e) {
                throw new SqlException(e);
            } finally {
                Utils.closeResulet(resultSet);
                Utils.closeStatement(stmt);
                close();
            }
        } else {

            PreparedStatement ps = null;
            ResultSet resultSet = null;
            try {
                ps = conn.prepareStatement(sqlString);
                Utils.prepare(ps, dialect, jsql);
                resultSet = ps.executeQuery();
                T t = extractor.extract(resultSet, dialect);
                return t;
            } catch (SQLException e) {
                throw new SqlException(e);
            } finally {
                Utils.closeResulet(resultSet);
                Utils.closePreparedStatement(ps);
                close();
            }
        }
    }

    /**
     * 执行更新
     *
     * 更新是面向数据库连接的，函数执行完毕后，不会关闭数据库连接
     *
     * @param keysExtractor 主键提取器
     * @return 更新的行数
     */
    @Override
    public Integer executeUpdate(Jsql jsql, KeysExtractor keysExtractor) {

        // 准备阶段
        Connection conn = getConnection();
        Dialect dialect = getDialect();

        if (Logger.isLogSql()) {
            jsql.print(dialect);
        }

        // 正式处理阶段
        String sqlString = jsql.getString();
        Statement stmt = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            int num = 0;
            if (keysExtractor == null) {
                ps = conn.prepareStatement(sqlString, Statement.NO_GENERATED_KEYS);
            } else {
                // 这种方式 mysql 是没问题的
                 ps = conn.prepareStatement(sqlString, Statement.RETURN_GENERATED_KEYS);
//                ps = conn.prepareStatement(sqlString, keysExtractor.getKeys());
            }

            // 处理参数
            Utils.prepare(ps, dialect, jsql);

            num = ps.executeUpdate();

            if (keysExtractor != null) {
                rs = ps.getGeneratedKeys();
                if (rs.next()) {
                    keysExtractor.setResult(num);
                    //
                    keysExtractor.fetchKeys(rs, dialect);
                }
            }

            return num;
        } catch (SQLException e) {
            throw new SqlException(e);
        } finally {
            Utils.closeResulet(rs);
            Utils.closePreparedStatement(ps);
            Utils.closeStatement(stmt);
            close();
        }
    }

}
